#include "ConvertOdb.h"

#ifdef _WIN32
#include <direct.h>
#include <io.h>
#else
#include <unistd.h>
#endif
#include <iostream>
#include <map>
#include <vector>

#include <Python.h>

#include "IBE_AbaqusOdbReader.h"
#include "IBE_DataInformationToVTK.h"
#include "IBE_Common.h"

static std::map<std::string, std::map<std::string, std::vector<std::string>>> seriesFilePathsMap_;

// ----------------------------------------------------------------------------
ConvertOdb::ConvertOdb()
{
}

// ----------------------------------------------------------------------------
ConvertOdb::~ConvertOdb()
{
}

// ----------------------------------------------------------------------------
int ConvertOdb::ConvertOdbToFile(std::string inputFile, std::string outputDir, int outType)
{
    if (outType != 0 && outType != 1)
    {
        return 0;
    }

    // 去除前后空格
    inputFile = ibe_common::IBE_Common::StringTrimmed(inputFile.c_str());
    outputDir = ibe_common::IBE_Common::StringTrimmed(outputDir.c_str());
    if (inputFile.empty() || outputDir.empty())
    {
        return 0;
    }

    Py_Initialize(); // 只调用一次
    PyRun_SimpleString("import sys;print(dir(sys.path))");
    if (!Py_IsInitialized()) // 判断是否初始化成功
    {
        std::cout << "Python Initialize failed." << std::endl;
        return 0;
    }

    seriesFilePathsMap_.clear();

    // 获取输入文件名
    std::string inFileName = inputFile;
    auto slashPos = inputFile.find_last_of("/");
    if (slashPos != std::string::npos)
    {
        inFileName = inputFile.substr(slashPos + 1);
    }

    std::string outFolderDir_vtk = "";
    std::string outFolderDir_gmsh = "";
    {
        auto dot_pos = inFileName.find_last_of('.');
        std::string fileName = inFileName;
        if (dot_pos != std::string::npos)
        {
            fileName = inFileName.substr(0, dot_pos);
        }
        outFolderDir_vtk = outputDir + "/" + fileName + ".vtk";
        outFolderDir_gmsh = outputDir + "/" + fileName + ".gmsh";
        // 判断文件是否存在:0-存在，-1-不存在 
        if (access(outFolderDir_vtk.c_str(), 0) == -1)
        {
            // 创建文件夹
#ifdef _WIN32
            mkdir(outFolderDir_vtk.c_str());
#else
            mkdir(outFolderDir_vtk.c_str(), 0755);
#endif
        }
        // 判断文件是否存在:0-存在，-1-不存在 
        if (access(outFolderDir_gmsh.c_str(), 0) == -1)
        {
            // 创建文件夹
#ifdef _WIN32
            mkdir(outFolderDir_gmsh.c_str());
#else
            mkdir(outFolderDir_gmsh.c_str(), 0755);
#endif
        }
    }

    int conVtkResult = ConvertOdb::ConvertOdbToVTK(inputFile, outFolderDir_vtk);
    if (outType == 1) // to gmsh
    {
        if (conVtkResult == 1 && !seriesFilePathsMap_.empty())
        {
            conVtkResult = ConvertOdb::ConvertOdbToGmsh(inputFile, outFolderDir_gmsh);
        }
        else
        {
            conVtkResult = 0;
        }
    }

    Py_Finalize(); // 只调用一次

    return conVtkResult;
}

// ----------------------------------------------------------------------------
int ConvertOdb::ConvertOdbToVTK(std::string inputFile, std::string outputDir)
{
    int convertState = 0;
    try
    {
        std::cout << "Start convert \"" << inputFile << "\" to \"" << outputDir << "\"." << std::endl;

        ibe_abaqus::IBE_AbaqusOdbReader* odb_reader = new ibe_abaqus::IBE_AbaqusOdbReader();
        odb_reader->SetFileName(inputFile.c_str());
        odb_reader->Update();

        std::cout << "[CONVERSION PROCESS]50%" << std::endl;

        ibe_common::IBE_DataInformation* dataInfo = odb_reader->GetDataInformation();
        if (dataInfo)
        {
            ibe_vtk::IBE_DataInformationToVTK* dataToVtk = new ibe_vtk::IBE_DataInformationToVTK();
            dataToVtk->SetDataInformation(dataInfo);
            dataToVtk->Update();
            
            std::cout << "[CONVERSION PROCESS]90%" << std::endl;
            
            seriesFilePathsMap_ = dataToVtk->WriteDataToVtk(outputDir.c_str());
            
            std::cout << "[CONVERSION PROCESS]100%" << std::endl;
            convertState = 1;

            delete dataToVtk;
            dataToVtk = nullptr;

            //std::cout << "Convert post vtk file succeed." << std::endl;
        }
        /*else
        {
            std::cerr << "Read odb file fialed!" << std::endl;
        }*/
        delete odb_reader;
        odb_reader = nullptr;
    }
    catch (...)
    {
        /*std::cerr << "Convert fialed." << std::endl;
        return 0;*/
    }

    return convertState;
}

// ----------------------------------------------------------------------------
int ConvertOdb::ConvertOdbToGmsh(std::string inputFile, std::string outputDir)
{
    int convertState = 0;
    std::vector<PyObject*> pyObjects;

    try
    {
        std::cout << "Start convert \"" << inputFile << "\" to \"" << outputDir << "\"." << std::endl;

        //导入模块 
        PyObject* module = PyImport_ImportModule("ConvertVtkToGmsh_ODB");
        if (!module)
        {
            std::logic_error ex("Python get module(ConvertVtkToGmsh_ODB) failed.");
            throw std::exception(ex);
        }
        pyObjects.emplace_back(module);

        std::cout << "[CONVERSION PROCESS] 25%" << std::endl;

        // vtk转gmsh的转换接口
        PyObject* func = PyObject_GetAttrString(module, "MultiVtkToGmsh");
        if (!func || !PyCallable_Check(func))
        {
            std::logic_error ex("Can't find the function(MultiVtkToGmsh).");
            throw std::exception(ex);
        }
        pyObjects.emplace_back(func);

        std::cout << "[CONVERSION PROCESS] 50%" << std::endl;

        // 构造参数
        std::vector<std::string> seriesFilePaths;
        for (auto& filePathsMapIter : seriesFilePathsMap_)
        {
            for (auto& filePathsIter : filePathsMapIter.second)
            {
                auto& filePaths = filePathsIter.second;
                for (auto& filePath : filePaths)
                {
                    seriesFilePaths.emplace_back(filePath);
                }
            }
        }
        PyObject* filePathList_py = PyList_New(seriesFilePaths.size());
        for (auto i = 0; i < seriesFilePaths.size(); i++)
        {
            std::string& filePath = seriesFilePaths.at(i);
            PyList_SetItem(filePathList_py, i, PyUnicode_FromString(filePath.c_str()));
        }
        pyObjects.emplace_back(filePathList_py);

        PyObject* func_args = PyTuple_New(2);
        PyTuple_SetItem(func_args, 0, filePathList_py);
        PyTuple_SetItem(func_args, 1, PyUnicode_FromString(outputDir.c_str()));
        pyObjects.emplace_back(func_args);

        std::cout << "[CONVERSION PROCESS] 75%" << std::endl;

        // 调用转换接口
        PyObject* func_py = PyObject_CallObject(func, func_args);
        if (!func_py)
        {
            std::logic_error ex("MultiVtkToGmsh failed.");
            throw std::exception(ex);
        }
        pyObjects.emplace_back(func_py);

        std::cout << "[CONVERSION PROCESS] 100%" << std::endl;
        convertState = 1;
    }
    catch (const std::exception& ex)
    {
        convertState = 0;
        std::cerr << "[ERROR] ConvertOdbToGmsh: " << ex.what() << std::endl;
        if (PyErr_Occurred())
        {
            PyErr_Print();
        }
    }

    // 释放python空间
    // Py_XDECREF和Py_DECREF功能相同，但可以处理空指针
    for (auto it = pyObjects.rbegin(); it != pyObjects.rend(); it++)
    {
        Py_XDECREF(*it); // 释放python空间
    }
    std::vector<PyObject*>().swap(pyObjects);

    return convertState;
}
